﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;

namespace Common
{
    /// <summary>
    /// 工厂帮助类
    /// 生产程序集中实现接口的类对象
    /// 程序集：Dll、Exe
    /// </summary>
    public class FactoryHelper
    {
        /// <summary>
        /// 程序集的目录
        /// </summary>
        private string AssemblyPath { get; set; }
        /// <summary>
        /// 程序集的文件名搜索匹配
        /// </summary>
        private string AssemblySearchPattern { get; set; }
        /// <summary>
        /// 程序集集合
        /// </summary>
        private List<Assembly> AssemblyList { get; set; }

        /// <summary>
        /// 工厂基础信息构造
        /// </summary>
        /// <param name="pluginPath">程序集的目录</param>
        /// <param name="assemblySearchPattern">程序集的文件名搜索匹配</param>
        public FactoryHelper(string assemblyPath, string assemblySearchPattern)
        {
            AssemblyPath = assemblyPath;
            AssemblySearchPattern = assemblySearchPattern;
        }

        /// <summary>
        /// 生产接口对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public List<T> Produce<T>() where T : class
        {
            List<T> result = new List<T>();

            try
            {
                LoadAssembly();
                AssemblyList.ForEach(
                    assembly => assembly.GetTypes().Where(type => type.IsPublic && !type.IsAbstract && typeof(T).IsAssignableFrom(type)).ToList().ForEach(
                        targetType => { if (Activator.CreateInstance(targetType, true) is T tmpT) result.Add(tmpT); }
                        )
                    );
                //GetImplTypeFromAssemblyList<T>().ForEach(type => { if (Activator.CreateInstance(type, true) is T tmpT) { result.Add(tmpT); } });
            }
            catch (Exception ex)
            {
                LogHelper.Error($"生产接口对象报错：{ex}");
            }

            return result;
        }

        #region 私有方法
        /// <summary>
        /// 从程序集集合中获取接口实现类类型
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        private List<Type> GetImplTypeFromAssemblyList<T>()
        {
            List<Type> result = new List<Type>();

            AssemblyList.ForEach(assembly => result.AddRange(assembly.GetTypes().Where(type => type.IsPublic && !type.IsAbstract && typeof(T).IsAssignableFrom(type))));

            return result;
        }

        /// <summary>
        /// 加载程序集
        /// </summary>
        /// <returns></returns>
        private void LoadAssembly()
        {
            if (AssemblyList == null)
            {
                if (!Path.IsPathRooted(AssemblyPath))
                {
                    AssemblyPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, AssemblyPath);
                }
                if (!Directory.Exists(AssemblyPath))
                {
                    Directory.CreateDirectory(AssemblyPath);
                }
                AssemblyList = new List<Assembly>();
                foreach (string file in Directory.GetFiles(AssemblyPath, AssemblySearchPattern))
                {
                    AssemblyList.Add(Assembly.Load(File.ReadAllBytes(file)));
                    //_pluginAssembly.Add(Assembly.LoadFrom(file));//此方式会占用组件
                }
            }
        }
        #endregion

    }
}